home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume9 / browse_pds < prev    next >
Encoding:
Text File  |  1989-12-14  |  40.8 KB  |  2,275 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v09i066: browse: screen-oriented directory browser
  4. Reply-To: peter@ficc.UUCP (Peter Da Silva)
  5.  
  6. Posting-number: Volume 9, Issue 66
  7. Submitted-by: peter@ficc.UUCP (Peter Da Silva)
  8. Archive-name: browse_pds
  9.  
  10. :
  11. #! /bin/sh
  12. # This is a shell archive, created at Ferranti International Controls Corp.
  13. # by peter (peter da silva,2810T 5180 @xds13) on Fri Nov 10 16:15:15 1989
  14. # Remove anything before the "#! /bin/sh" line, then unpack it by saving
  15. # it into a file and typing "sh file".  If you do not have sh, you need 
  16. # unshar, a dearchiving program which is widely available.  In the absolute
  17. # wost case, you can crack the files out by hand.
  18. # If the archive is complete, you will see the message "End of archive."
  19. # at the end.
  20. # This archive contains the following files...
  21. # 'Makefile'
  22. # 'browse.doc'
  23. # 'browse.c'
  24. # To extract them, run the following through /bin/sh
  25. echo x - Makefile
  26. sed 's/^X//' > Makefile << '//END_OF_FILE'
  27. XCFILES=browse.c
  28. XOFILES=$(CFILES:.c=.o)
  29. XTFILES=Makefile browse.doc $(CFILES)
  30. XCFLAGS=-O
  31. XLFLAGS=-O
  32. XLIBS=-ltermlib
  33. X
  34. Xbrowse: $(OFILES)
  35. X    $(CC) $(LFLAGS) $(OFILES) -o browse $(LIBS)
  36. X
  37. Xbrowse.shar: $(TFILES)
  38. X    shar $(TFILES) > browse.shar
  39. //END_OF_FILE
  40. echo x - browse.doc
  41. sed 's/^X//' > browse.doc << '//END_OF_FILE'
  42. XBrowse is a screen-oriented directory browser, based on the metaphor of using
  43. X'VI' to edit an 'ls -l' listing.
  44. X
  45. XCommands:
  46. X    SPACE    Enter a subdirectory, or display a file.
  47. X    &    Run a program that won't clobber the screen.
  48. X    !    Run a program.
  49. X    =    Enter a directory name.
  50. X    ?    Peek at the current file.
  51. X    [    Define a macro.
  52. X    H    Go to the top of the page.
  53. X    J    Go to the bottom of the directory.
  54. X    K    Go to the top of the directory.
  55. X    L    Go to the bottom of the page.
  56. X    ^L    Repaint screen.
  57. X    M    Display macros.
  58. X    N,^F    Go down 20 lines.
  59. X    P,^B    Go up 20 lines.
  60. X    R    Rename a file.
  61. X    S    Save definitions.
  62. X    dd    Delete file(s). (ask for verification)
  63. X    DD    Delete file(s).
  64. X    h    Place cursor at beginning of line.
  65. X    l    Move cursor to end of line.
  66. X    <    Display file names only.
  67. X    >    Display long directory listing.
  68. X    +    Make a file permanent.
  69. X    (    Make the current file permanent.
  70. X    )    Make the current file non-permanent.
  71. X    j,^J    Go down a line.
  72. X    k,^K    Go up a line.
  73. X    n,^D    Go down 11 lines.
  74. X    p,^U    Go up 11 lines.
  75. X
  76. X    qq,QQ,ZZ    Exit.
  77. X
  78. X    r    Re-read directories.
  79. X
  80. X    t    Toggle tag on current file.
  81. X    T    Tag all files.
  82. X    U    Untag all files.
  83. X
  84. XMacros:
  85. X    [xtext]    Define x as text.
  86. X
  87. XWithin text:
  88. X    %    Current filename.
  89. X    #    Current directory.
  90. X    !    Previous command.
  91. X    $x    Macro for key x
  92. X    $$    Current process ID
  93. X    ~    Home directory.
  94. X    ^K    One character from previous command.
  95. X    @x    Execute macro for key x
  96. X    \x    Enter special character x
  97. X    \nnn    nnn, octal
  98. X    \^x    Control-x
  99. X
  100. XDefault macros:
  101. X    SPACE    !more %<CR>
  102. X    %    !%<CR>
  103. X    .    =.
  104. X    /    =/
  105. X    ~    =~
  106. X    v    !vi %<CR>
  107. X    $    !vi /tmp/br.env.$$<CR>
  108. X            -- this file is loaded as your environment
  109. X            -- whenever you run a program.
  110. X
  111. XThe contents of the environment variable BROWSE are executed as a macro
  112. Xwhen you start up.
  113. //END_OF_FILE
  114. echo x - browse.c
  115. sed 's/^X//' > browse.c << '//END_OF_FILE'
  116. X/*             -- Just what the hell am I ??? ---                            */
  117. X
  118. X#include <stdio.h>
  119. X#ifdef M_XENIX
  120. X#define USG
  121. X#define rindex strrchr
  122. X#define GETCWD
  123. X#else
  124. X#ifdef L_ctermid
  125. X#define USG
  126. X#define rindex strrchr
  127. X#define minor(i) ((i)&0xFF)
  128. X#define major(i) minor((i)>>8)
  129. X#else
  130. X#include <whoami.h>
  131. X#endif
  132. X#endif
  133. X
  134. X/*         -- Miscellaneous include files --                     */
  135. X
  136. X#include <sys/param.h>            /* NCARGS, and others */
  137. X#ifndef M_XENIX
  138. X#include <sys/types.h>                       /* data types for various files */
  139. X#endif
  140. X#include <sys/stat.h>         /* stat data structure for getdir(), statout() */
  141. X#include <sys/dir.h>                      /* dir data structure for getdir() */
  142. X#include <pwd.h>                       /* passwd data structure for u_name() */
  143. X#include <grp.h>                        /* group data structure for g_name() */
  144. X#ifdef BSD
  145. X#include <sys/time.h>                  /* time data structure for printime() */
  146. X#else
  147. X#include <time.h>                       /* time data structure for printime() */
  148. X#endif
  149. X#ifdef USG
  150. X#ifdef M_XENIX
  151. X#include <sys/ioctl.h>
  152. X#endif
  153. X#include <termio.h>
  154. X#else
  155. X#include <sgtty.h>                     /* terminal modes for tinit(), tend() */
  156. X#endif
  157. X#include <signal.h>
  158. X
  159. X/*        -- make information --
  160. XBUILD
  161. Xbrowse: browse.c
  162. X    cc browse.c -O -o browse -ltermlib
  163. XEND
  164. X*/
  165. X
  166. X/*        -- Miscellaneous defines --                     */
  167. X#define FALSE 0
  168. X#define TRUE 1
  169. X
  170. X#define MAXENTS 320
  171. X#define MAXID 16
  172. X#define MAXLINE 81
  173. X#define NCOL 64
  174. X#define MAXNAME 14
  175. X#define FILENAME 256
  176. X#define MAXARGC (NCARGS/16)    /* Estimate max ARGC */
  177. X#define CHARSET 256        /* Number of macros == size of byte */
  178. X#define NOMAC (0)        /* Null macro (last) */
  179. X#define TERMBUF 1024        /* Size of term buf for termcap */
  180. X#define SMALLBUF 256
  181. X
  182. X/*        -- Extended directory entry format --                 */
  183. Xstruct entry {
  184. X    char *e_name;
  185. X    int e_flags;
  186. X#define FTAGGED (1<<0)
  187. X#define FPERMANENT (1<<1)
  188. X    struct stat e_stat;                             /* file status field */
  189. X    char e_uname[9];                                        /* user name */
  190. X    char e_gname[9];                                /* user's group name */
  191. X} 
  192. X*xentries[MAXENTS], **entries=xentries;
  193. Xint nentries;
  194. X
  195. X/*        -- Look-up cache for user names --                 */
  196. Xstruct idtab {
  197. X    int  id_id;                                    /* user (or group) id */
  198. X    char id_name[9];                                 /* name[8] + filler */
  199. X} 
  200. Xu_list[MAXID],                                       /* Matched user id's. */
  201. Xg_list[MAXID];                                              /* ditto group */
  202. Xint u_ptr=0, g_ptr=0;                                     /* current entries */
  203. X
  204. X/*        -- Global variables --                         */
  205. XFILE *efp;                                               /* Environment file */
  206. Xchar efname[MAXLINE];                                              /* " name */
  207. Xchar *tent;                                               /* Pointer to tbuf */
  208. Xchar PC;                                                    /* Pad character */
  209. Xchar *UP, *BC;                                /* Upline, backsapce character */
  210. Xshort ospeed;                                       /* Terminal output speed */
  211. Xchar termbuf[TERMBUF];                   /* Place to put term info */
  212. X
  213. Xchar *macbuf[CHARSET], ungetbuf[SMALLBUF];         /* Buffers for pushback and macros */
  214. Xchar c_macro=NOMAC;                                           /* current macro */
  215. Xchar *macptr = "";                   /* Pointer to currently executing macro */
  216. Xchar *ungetptr = ungetbuf;              /* Pointer to pushed-back characters */
  217. X
  218. Xchar *errname;                                /* Name of file error found in */
  219. Xextern int errno;                                     /* system error number */
  220. Xint xerrno;                                         /* extended error number */
  221. Xint ccol=NCOL;                /* Width of used display, current column */
  222. Xint quickmode;              /* short display mode (files only) */
  223. X
  224. X#ifdef USG
  225. Xstruct termio rawbuf;
  226. Xstruct termio cookedbuf;
  227. X#else
  228. Xstruct sgttyb sgbuf;                        /* buffer for terminal mode info */
  229. Xint rawflags, cookflags;          /* flags for raw & cooked tty mode */
  230. X#endif
  231. X
  232. Xchar *cm,                                                   /* Cursor motion */
  233. X     *cs,                                         /* Change scrolling region */
  234. X     *sf,                                         /*  - scroll forward       */
  235. X     *sr,                                         /*  - scroll backwards     */
  236. X     *ce,                                            /* Clear to end of line */
  237. X     *cl,                                                    /* Clear screen */
  238. X     *al,                                                     /* Insert line */
  239. X     *dl,                                                    /* delete ditto */
  240. X     *so,                                                        /* standout */
  241. X     *se,                                                    /* standout end */
  242. X     *us,                                                       /* underline */
  243. X     *ue,                                                   /* underline end */
  244. X     *ti,                            /* Init terminal */
  245. X     *te;                           /* Reset terminal */
  246. Xint  li,                                                  /* lines on screen */
  247. X     co;                                                    /* columns ditto */
  248. Xchar xn;        /* Magic cookie kludge */
  249. X
  250. X/*        -- Global error messages --                     */
  251. Xchar *emesg[4]={
  252. X    "??",
  253. X#define TOO_MANY 1
  254. X    "Too many directory entries",
  255. X#define NOMATCH 2
  256. X    "No match",
  257. X    0
  258. X};
  259. X
  260. Xint    top, curr;               /* Positions of screen in directory */
  261. X#define bottom ((top+nlines>nentries)?nentries:(top+nlines))
  262. Xchar    *dot;                                   /* name of current directory */
  263. Xint    nlines;                         /* number of lines displayed on page */
  264. Xchar    display_up;                               /* Does the display exist? */
  265. Xint    todump=1;                 /* Do we want to dump data? */
  266. Xint    ended;                                    /* Have we quite finished? */
  267. Xint    intrup;                    /* Have we been interrupted? */
  268. Xchar    *HOME;                      /* Where did I start from? */
  269. Xchar    *SHELL;                       /* How do I run programs? */
  270. X
  271. X/*        -- types of functions !!!                     */
  272. Xchar *getenv(), *tgetstr();
  273. Xchar *malloc();
  274. X
  275. X#define NEW(t) (t *)malloc(sizeof (t))
  276. X#define NIL(t) ((t) 0)
  277. X
  278. X/*        -- Code starts here: dummy main --                    */
  279. Xmain(ac, av, ep)
  280. Xint ac;
  281. Xchar **av;
  282. Xchar **ep;
  283. X{
  284. X    if(ac>1) chdir(av[1]);
  285. X
  286. X    sprintf(efname, "/tmp/br.env.%d", getpid());
  287. X    HOME=getenv("HOME");
  288. X    SHELL=getenv("SHELL");
  289. X    dumpenv(ep);
  290. X
  291. X    intrup=0;
  292. X    tinit(getenv("TERM"));
  293. X    clear_all();
  294. X    browse();
  295. X    tend();
  296. X    unlink(efname);
  297. X}
  298. X
  299. Xclear_all()
  300. X{
  301. X    int i;
  302. X
  303. X    for(i = 0; i < MAXENTS; i++)
  304. X        entries[i] = 0;
  305. X}
  306. X
  307. Xchar *clone(name)
  308. Xchar *name;
  309. X{
  310. X    char *hold;
  311. X    
  312. X    hold = (char *)malloc(strlen(name)+1);
  313. X
  314. X    if(hold==0)
  315. X        return 0;
  316. X    strcpy(hold, name);
  317. X    return hold;
  318. X}
  319. X
  320. Xnewname(e, name)
  321. Xstruct entry *e;
  322. Xchar *name;
  323. X{
  324. X    if(e->e_name)
  325. X        free(e->e_name);
  326. X    e->e_name = clone(name);
  327. X}
  328. X
  329. X#if BSD
  330. Xreadent(dp, db)
  331. XDIR *dp;
  332. Xstruct direct *db;
  333. X{
  334. X    struct direct *ptr;
  335. X
  336. X    ptr = readdir(dp);
  337. X    if(!ptr) return 0;
  338. X
  339. X    *db = *ptr;    /* V7 'C' and above... safe, since UCB=V7+ */
  340. X    free(ptr);
  341. X    return 1;
  342. X}
  343. X#else
  344. X#define opendir(n) fopen(n, "r")
  345. X#define DIR FILE
  346. Xreadent(dp, db)
  347. XDIR *dp;
  348. Xstruct direct *db;
  349. X{
  350. X    if(fread(db, sizeof(struct direct), 1, dp))
  351. X        return 1;
  352. X    /* else */
  353. X        return 0;
  354. X}
  355. X#define closedir fclose
  356. X#endif
  357. X
  358. Xgetdir()
  359. X{
  360. X    char *u_name(), *g_name();
  361. X    DIR *dp;
  362. X    int  valid;
  363. X    struct direct *hold = NEW(struct direct);
  364. X    int i, p;
  365. X
  366. X    if(!(dp = opendir("."))) {
  367. X        errname=".";
  368. X        return FALSE;
  369. X    }
  370. X
  371. X    p = 0;
  372. X    for(i = 0; i < nentries; i++) {
  373. X        if(entries[i]->e_flags & FPERMANENT) {
  374. X            if(p != i) {
  375. X                struct entry *hold;
  376. X                hold = entries[p];
  377. X                entries[p] = entries[i];
  378. X                entries[i] = hold;
  379. X            }
  380. X            p++;
  381. X        }
  382. X    }
  383. X
  384. X    for(nentries = p; !intrup && nentries < MAXENTS; nentries += valid) {
  385. X
  386. X        if(!entries[nentries]) {
  387. X            entries[nentries] = NEW(struct entry);
  388. X            if(!entries[nentries])
  389. X                break;
  390. X            entries[nentries]->e_name = NIL(char *);
  391. X        }
  392. X
  393. X        if(!readent(dp, hold))
  394. X            break;
  395. X
  396. X        valid = (hold->d_ino != 0);
  397. X        if(valid) {
  398. X            if(stat(hold->d_name, &entries[nentries]->e_stat)==-1) {
  399. X                closedir(dp);
  400. X                errname=hold->d_name;
  401. X                free(hold);
  402. X                return FALSE;
  403. X            }
  404. X
  405. X            newname(entries[nentries], hold->d_name);
  406. X
  407. X#ifndef BSD /* truncate name to 14 characters in non-BSD systems */
  408. X            if(strlen(entries[nentries]->e_name)>14)
  409. X                entries[nentries]->e_name[14] = 0;
  410. X#endif
  411. X
  412. X            entries[nentries]->e_flags = 0;
  413. X
  414. X            strcpy(entries[nentries]->e_uname,
  415. X                u_name(entries[nentries]->e_stat.st_uid));
  416. X
  417. X            strcpy(entries[nentries]->e_gname,
  418. X                g_name(entries[nentries]->e_stat.st_gid));
  419. X        }
  420. X    }
  421. X
  422. X    closedir(dp);
  423. X
  424. X    free(hold);
  425. X
  426. X    if(intrup)
  427. X        return FALSE;
  428. X
  429. X    if(nentries>=MAXENTS || entries[nentries]==NIL(struct entry *)) {
  430. X        errno=0;
  431. X        xerrno=TOO_MANY;
  432. X        errname=".";
  433. X        return FALSE;
  434. X    }
  435. X
  436. X    sortdir();
  437. X
  438. X    if(intrup)
  439. X        return FALSE;
  440. X    return TRUE;
  441. X}
  442. X
  443. Xat_current()
  444. X{
  445. X    at_file(curr);
  446. X}
  447. X
  448. Xat_file(file)
  449. Xint file;
  450. X{
  451. X    if(display_up) {
  452. X        if(file < top || file >= top+nlines)
  453. X            return 0;
  454. X        at(0, curr-top+2);
  455. X    } else {
  456. X        if(file != curr)
  457. X            return 0;
  458. X        cmdline();
  459. X    }
  460. X    return 1;
  461. X}
  462. X
  463. Xdisplay_flags(flags)
  464. X{
  465. X    outc((flags&FTAGGED)?'+':((flags&FPERMANENT)?'!':' '));
  466. X}
  467. X
  468. Xrepaint_flags()
  469. X{
  470. X    if(!display_up) return;
  471. X    at(NCOL-1, curr-top+2);
  472. X    display_flags(entries[curr]->e_flags);
  473. X}
  474. X
  475. Xrepaint_current()
  476. X{
  477. X    if(!display_up) return;
  478. X    at_current();
  479. X    dump(curr, curr+1);
  480. X}
  481. X
  482. Xtag()
  483. X{
  484. X    entries[curr]->e_flags ^= FTAGGED;
  485. X    repaint_flags();
  486. X}
  487. X
  488. Xtag_all(flag)
  489. Xint flag;
  490. X{
  491. X    int i;
  492. X
  493. X    for(i = 0; i < nentries; i++)
  494. X        if(flag)
  495. X            entries[i]->e_flags |= FTAGGED;
  496. X        else
  497. X            entries[i]->e_flags &= ~FTAGGED;
  498. X    if(display_up)
  499. X        todump = TRUE;
  500. X}
  501. X
  502. Xdelete_from_display(file)
  503. Xint file;
  504. X{
  505. X    if(!display_up) return;
  506. X
  507. X    if(file>=top+nlines) return;
  508. X
  509. X    if(file < top) file = top;
  510. X
  511. X    scroll(2+file-top, 2+nlines, 1);
  512. X    at(0, 2+nlines-1);
  513. X    if(top+nlines >= nentries)
  514. X        outc('~');
  515. X    else
  516. X        dump(bottom, bottom+1);
  517. X}
  518. X        
  519. Xdelete_file_entry(file)
  520. Xint file;
  521. X{
  522. X    struct entry *hold;
  523. X    int    i;
  524. X
  525. X    delete_from_display(file);
  526. X
  527. X    hold = entries[file];
  528. X    for(i=file; i<nentries-1; i++)
  529. X        entries[i]=entries[i+1];
  530. X    entries[nentries-1]=hold;
  531. X    nentries--;
  532. X
  533. X    if(file < curr || curr >= nentries) {
  534. X        curr--;
  535. X        if(top >= nentries) {
  536. X            top--;
  537. X            display_up = 0;
  538. X            todump = 1;
  539. X        }
  540. X    }
  541. X} 
  542. X
  543. Xremove_one(file, doit)
  544. Xint file;
  545. Xint doit;
  546. X{
  547. X    if(!doit) {
  548. X        cmdline();
  549. X        outs("Delete ");
  550. X        ctlouts(entries[file]->e_name);
  551. X        outs(" [n]?");
  552. X        doit = getchar() == 'y';
  553. X        outs(doit?"Yes.":"No.");
  554. X    }
  555. X    if(doit) {
  556. X        if(unlink(entries[file]->e_name) == 0) {
  557. X            cmdline();
  558. X            outs("Deleted ");
  559. X            ctlouts(entries[file]->e_name);
  560. X            outs(".");
  561. X            delete_file_entry(file);
  562. X            return 1;
  563. X        } else {
  564. X            wperror(entries[file]->e_name);
  565. X            return 0;
  566. X        }
  567. X    }
  568. X    return 0;
  569. X} 
  570. X
  571. Xremove(doit)
  572. Xint doit;
  573. X{
  574. X    int i;
  575. X    int found_tags;
  576. X
  577. X    found_tags = 0;
  578. X    i = 0;
  579. X    while(i < nentries) {
  580. X        if(entries[i]->e_flags & FTAGGED) {
  581. X            found_tags = 1;
  582. X            if(!remove_one(i, doit)) /* decrements nentries */
  583. X                break;
  584. X        } else
  585. X            i++;
  586. X    }
  587. X    if(!found_tags)
  588. X        remove_one(curr, doit);
  589. X}
  590. X
  591. Xinsert_entry_at(ent, i)
  592. Xstruct entry *ent;
  593. Xint i;
  594. X{
  595. X    struct entry *hold;
  596. X    int j;
  597. X
  598. X    /* Allocate slot at end */
  599. X    if(!entries[nentries]) {
  600. X        entries[nentries] = NEW(struct entry);
  601. X        if(!entries[nentries])
  602. X            return 0;
  603. X        entries[nentries]->e_name = NIL(char *);
  604. X    } else if(entries[nentries]->e_name) {
  605. X        free(entries[nentries]->e_name);
  606. X        entries[nentries]->e_name = NIL(char *);
  607. X    }
  608. X
  609. X    /* Copy data into slot */
  610. X    *entries[nentries] = *ent;
  611. X    entries[nentries]->e_name = clone(ent->e_name);
  612. X    if(!entries[nentries]->e_name)
  613. X        return 0;
  614. X
  615. X    if(i != nentries) {
  616. X        /* Rotate slot to middle */
  617. X        hold = entries[nentries];
  618. X        for(j = nentries; j > i; j--)
  619. X            entries[j] = entries[j-1];
  620. X        entries[i] = hold;
  621. X    }
  622. X    nentries++;
  623. X
  624. X    if(display_up) {
  625. X        if(i < top)
  626. X            i = top;
  627. X        if(i >= bottom)
  628. X            return;
  629. X        scroll(2+i-top, 2+nlines, -1);
  630. X        at(0, 2+i-top);
  631. X        dump(i, i+1);
  632. X    }
  633. X}
  634. X
  635. Xinsert_entry(ent)
  636. Xstruct entry *ent;
  637. X{
  638. X    int i;
  639. X
  640. X    if(nentries >= MAXENTS)
  641. X        return 0;
  642. X
  643. X    for(i = 0; i < nentries; i++)
  644. X        if(entcmp(&ent, &entries[i]) < 0)
  645. X            break;
  646. X
  647. X    return insert_entry_at(ent, i);
  648. X}
  649. X
  650. Xmove()
  651. X{
  652. X    char scratch[FILENAME];
  653. X    struct entry hold;
  654. X    char inps();
  655. X
  656. X    hold = *entries[curr];
  657. X
  658. X    cmdline();
  659. X    outs("Rename ");
  660. X    ctlouts(entries[curr]->e_name);
  661. X    outc(' ');
  662. X    if(inps(scratch, entries[curr]->e_name, 0)=='\033') {
  663. X        killcmd();
  664. X        return;
  665. X    }
  666. X    if(link(entries[curr]->e_name, scratch)!=0) {
  667. X        char tmbuf[42];
  668. X        sprintf(tmbuf, "(rename %s %s)", entries[curr]->e_name, scratch);
  669. X        wperror(tmbuf);
  670. X        return;
  671. X    }
  672. X    if(unlink(entries[curr]->e_name)!=0) {
  673. X        wperror(entries[curr]->e_name);
  674. X        return;
  675. X    }
  676. X
  677. X    hold.e_name = scratch;
  678. X    hold.e_flags &= ~FTAGGED;
  679. X
  680. X    delete_file_entry(curr);
  681. X    insert_entry(&hold);
  682. X}
  683. X
  684. Xpname(name, mode)
  685. Xchar *name;
  686. Xint mode;
  687. X{
  688. X    int i;
  689. X    char *slash, *rindex();
  690. X    int max=quickmode?MAXLINE:(MAXNAME+1);
  691. X
  692. X    if((mode&S_IFMT)==S_IFDIR)
  693. X        max--;
  694. X    else if((mode&S_IFMT)==S_IFREG && (mode&0111))
  695. X        max--;
  696. X    else if((mode&S_IFMT)!=S_IFREG)
  697. X        max--;
  698. X
  699. X    if(!quickmode && (slash=rindex(name, '/'))) {
  700. X        name=slash;
  701. X        outc('<');
  702. X        max--;
  703. X    }
  704. X    for(i=0; i<max && *name; name++)
  705. X        i += ctlout(*name);
  706. X    standend();
  707. X    if(i==max && *name)
  708. X        outs("\b>");
  709. X    if((mode&S_IFMT)==S_IFDIR) {
  710. X        outc('/');
  711. X    }
  712. X    else if((mode&S_IFMT)==S_IFREG && (mode&0111)) {
  713. X        outc('*');
  714. X    }
  715. X    else if((mode&S_IFMT)!=S_IFREG) {
  716. X        outc('?');
  717. X    }
  718. X}
  719. X
  720. Xsortdir()
  721. X{
  722. X    int   entcmp();
  723. X    qsort(entries, nentries, sizeof(struct entry *), entcmp);
  724. X}
  725. X
  726. Xaddname(flag)
  727. Xchar flag;
  728. X{
  729. X    char buf[FILENAME], *ptr, *tmp;
  730. X    char scratch[FILENAME];
  731. X    struct entry hold;
  732. X    char inps();
  733. X
  734. X    cmdline();
  735. X    outs("Add ");
  736. X    if(inps(scratch, entries[curr]->e_name, 0)=='\033') {
  737. X        killcmd();
  738. X        return;
  739. X    }
  740. X    
  741. X    if(stat(scratch, &hold.e_stat)==-1) {
  742. X        wperror(scratch);
  743. X        return;
  744. X    }
  745. X    if(flag!='+' && *scratch != '/') {
  746. X        strcpy(buf, dot);
  747. X        ptr = scratch;
  748. X        for(;;) {    /* eat '../' and './' */
  749. X            if(ptr[0]=='.' && ptr[1]=='.' &&
  750. X               (ptr[2]=='/' || !ptr[2])) {
  751. X                tmp = rindex(buf, '/');
  752. X                if(!tmp) break;
  753. X                *tmp=0;
  754. X                ptr += 2+(ptr[2]=='/');
  755. X                continue;
  756. X            }
  757. X            if(ptr[0]=='.' && 
  758. X               (ptr[1]=='/' || !ptr[1])) {
  759. X                ptr += 1+(ptr[1]=='/');
  760. X                continue;
  761. X            }
  762. X            break;
  763. X        }
  764. X        if(*ptr) {
  765. X            strcat(buf, "/");
  766. X            strcat(buf, ptr);
  767. X        }
  768. X        hold.e_name = buf;
  769. X    } else
  770. X        hold.e_name = scratch;
  771. X    strcpy(hold.e_uname,
  772. X        u_name(hold.e_stat.st_uid));
  773. X    strcpy(hold.e_gname,
  774. X        g_name(hold.e_stat.st_gid));
  775. X    hold.e_flags = 0;
  776. X    if(flag!='+')
  777. X        hold.e_flags |= FPERMANENT;
  778. X    insert_entry(&hold);
  779. X}
  780. X
  781. Xaddperm()
  782. X{
  783. X    char buf[FILENAME], *ptr, *tmp;
  784. X    struct entry hold;
  785. X    int   entcmp(), i;
  786. X
  787. X    if(entries[curr]->e_flags & FPERMANENT)
  788. X        return;
  789. X
  790. X    if(entries[curr]->e_name[0]!='/') {
  791. X        strcpy(buf, dot);
  792. X        ptr = entries[curr]->e_name;
  793. X        for(;;) {    /* eat '../' and './' */
  794. X            if(ptr[0]=='.' && ptr[1]=='.' &&
  795. X               (ptr[2]=='/' || !ptr[2])) {
  796. X                tmp = rindex(buf, '/');
  797. X                if(!tmp) break;
  798. X                *tmp=0;
  799. X                ptr += 2+(ptr[2]=='/');
  800. X                continue;
  801. X            }
  802. X            if(ptr[0]=='.' && 
  803. X               (ptr[1]=='/' || !ptr[1])) {
  804. X                ptr += 1+(ptr[1]=='/');
  805. X                continue;
  806. X            }
  807. X            break;
  808. X        }
  809. X        if(*ptr) {
  810. X            strcat(buf, "/");
  811. X            strcat(buf, ptr);
  812. X        }
  813. X        hold = *entries[curr];
  814. X
  815. X        hold.e_name = buf;
  816. X        hold.e_flags &= ~FTAGGED;
  817. X        hold.e_flags |= FPERMANENT;
  818. X        insert_entry(&hold);
  819. X    } else {
  820. X        entries[curr]->e_flags |= FPERMANENT;
  821. X        entries[curr]->e_flags &= ~FTAGGED;
  822. X        repaint_flags();
  823. X    }
  824. X}
  825. X
  826. Xdelperm()
  827. X{
  828. X    entries[curr]->e_flags &= ~(FPERMANENT|FTAGGED);
  829. X    repaint_flags();
  830. X}
  831. X
  832. Xentcmp(e1, e2)
  833. Xstruct entry **e1, **e2;
  834. X{
  835. X    if((*e1)->e_name[0] == '/') {
  836. X        if((*e2)->e_name[0] != '/')
  837. X            return 1;
  838. X    } else if((*e2)->e_name[0] == '/')
  839. X        return -1;
  840. X
  841. X    return strcmp((*e1)->e_name, (*e2)->e_name);
  842. X}
  843. X
  844. Xdump(start, end)
  845. Xint start;
  846. Xint end;
  847. X{
  848. X    int  i;
  849. X    int  lo = (start<nentries)?start:nentries;
  850. X    int  hi = (end<nentries)?end:nentries;
  851. X
  852. X    for(i=lo; i<hi; i++) {
  853. X        statout(entries[i]->e_name,
  854. X        &entries[i]->e_stat,
  855. X        entries[i]->e_uname,
  856. X        entries[i]->e_gname,
  857. X        entries[i]->e_flags);
  858. X        nl();
  859. X    }
  860. X    return TRUE;
  861. X}
  862. X
  863. Xstatout(name, sbuf, user, group, flags)
  864. Xchar *name;
  865. Xstruct stat *sbuf;
  866. Xchar *user, *group;
  867. Xint flags;
  868. X{
  869. X    int mode = sbuf->st_mode;
  870. X
  871. X    if(!quickmode) {
  872. X        printf("%5u ", sbuf->st_ino);
  873. X
  874. X        if((mode&S_IFMT)==S_IFCHR) outc('c');
  875. X        else if((mode&S_IFMT)==S_IFBLK) outc('b');
  876. X        else if((mode&S_IFMT)==S_IFDIR) outc('d');
  877. X        else if((mode&S_IFMT)==S_IFREG) outc('-');
  878. X        else outc('?');
  879. X        triad((mode>>6)&7, mode&S_ISUID, 's');
  880. X        triad((mode>>3)&7, mode&S_ISGID, 's');
  881. X        triad(mode&7, mode&S_ISVTX, 't');
  882. X        outc(' ');
  883. X
  884. X        printf("%3u ", sbuf->st_nlink);
  885. X        printf("%-8s ", user);
  886. X        printf("%-8s ", group);
  887. X
  888. X        if((mode&S_IFMT)==S_IFREG || (mode&S_IFMT)==S_IFDIR)
  889. X            printf("%7ld ", sbuf->st_size);
  890. X        else
  891. X            printf("%3d,%3d ",
  892. X            major(sbuf->st_rdev),
  893. X            minor(sbuf->st_rdev));
  894. X
  895. X        outc(' ');
  896. X        printime(&sbuf->st_mtime);
  897. X    }
  898. X
  899. X    display_flags(flags);
  900. X    pname(name, sbuf->st_mode);
  901. X}
  902. X
  903. Xchar *
  904. Xu_name(uid)
  905. Xint uid;
  906. X{
  907. X    int  i;
  908. X    struct passwd *pwptr, *getpwuid();
  909. X
  910. X    for(i=0; i<u_ptr; i++)
  911. X        if(u_list[i].id_id==uid)
  912. X            return u_list[i].id_name;
  913. X
  914. X    if(u_ptr>=MAXID)                                       /* cache full */
  915. X        u_ptr = 0;        /* simplistic algorithm, wrap to beginning */
  916. X    /* with MAXID >> # common id's it's good enough */
  917. X
  918. X    u_list[u_ptr].id_id=uid;
  919. X
  920. X    if(pwptr=getpwuid(uid)) { /* Copy name */
  921. X        for(i=0; pwptr->pw_name[i]>' '; i++)
  922. X            u_list[u_ptr].id_name[i]=pwptr->pw_name[i];
  923. X        u_list[u_ptr].id_name[i]=0;
  924. X    } 
  925. X    else /* Default to UID */
  926. X        sprintf(u_list[u_ptr].id_name, "%d", uid);
  927. X
  928. X    return u_list[u_ptr++].id_name;
  929. X}
  930. X
  931. Xchar *
  932. Xg_name(gid)
  933. Xint gid;
  934. X{
  935. X    int  i;
  936. X    struct group *grptr, *getgrgid();
  937. X
  938. X    for(i=0; i<g_ptr; i++)
  939. X        if(g_list[i].id_id==gid)
  940. X            return g_list[i].id_name;
  941. X
  942. X    if(g_ptr>=MAXID)                                       /* cache full */
  943. X        g_ptr = 0;        /* simplistic algorithm, wrap to beginning */
  944. X    /* with MAXID >> # common id's it's good enough */
  945. X
  946. X    g_list[g_ptr].id_id=gid;
  947. X
  948. X    if(grptr=getgrgid(gid)) { /* Copy name */
  949. X        for(i=0; grptr->gr_name[i]>' '; i++)
  950. X            g_list[g_ptr].id_name[i]=grptr->gr_name[i];
  951. X        g_list[g_ptr].id_name[i]=0;
  952. X    } 
  953. X    else /* Default to UID */
  954. X        sprintf(g_list[g_ptr].id_name, "%d", gid);
  955. X
  956. X    return g_list[g_ptr++].id_name;
  957. X}
  958. X
  959. Xprintime(clock)
  960. Xlong *clock;
  961. X{
  962. X    struct tm *tmbuf, *localtime();
  963. X    static char *months[12]= {
  964. X        "Jan","Feb","Mar","Apr","May","Jun",
  965. X        "Jul","Aug","Sep","Oct","Nov","Dec"
  966. X    };
  967. X
  968. X    tmbuf=localtime(clock);
  969. X    printf("%2d %3s %02d %2d:%02d",
  970. X    tmbuf->tm_mday,
  971. X    months[tmbuf->tm_mon],
  972. X    tmbuf->tm_year,
  973. X    tmbuf->tm_hour,
  974. X    tmbuf->tm_min);
  975. X}
  976. X
  977. Xheader()
  978. X{
  979. X    int    i;
  980. X    if(quickmode)
  981. X        printf(" File Name");
  982. X    else
  983. X        printf(
  984. X"Inode Long mode  LNX User     Group   Size/Dev  Modify Time     File name"
  985. X            );
  986. X    nl();
  987. X}
  988. X
  989. Xtriad(bits, special, code)
  990. Xint bits, special;
  991. Xchar code;
  992. X{
  993. X    if(bits&4) outc('r');
  994. X    else outc('-');
  995. X
  996. X    if(bits&2) outc('w');
  997. X    else outc('-');
  998. X
  999. X    if(special) outc(code);
  1000. X    else if(bits&1) outc('x');
  1001. X    else outc('-');
  1002. X}
  1003. X
  1004. Xouts(s)
  1005. Xchar *s;
  1006. X{
  1007. X    int  outc();
  1008. X
  1009. X    if(s)
  1010. X        tputs(s, 0, outc);
  1011. X}
  1012. X
  1013. Xoutc(c)
  1014. Xchar c;
  1015. X{
  1016. X    putchar(c);
  1017. X}
  1018. X
  1019. X/* Screen manipulation primitives: dumb set for smart terminals */
  1020. Xat(x, y)
  1021. Xint x, y;
  1022. X{
  1023. X    outs(tgoto(cm, x, y));
  1024. X}
  1025. X
  1026. Xnl()
  1027. X{
  1028. X    outs(ce);
  1029. X    outc('\n');
  1030. X}
  1031. X
  1032. X
  1033. X/* Scroll lines in window (from:to) n lines */
  1034. Xscroll(from, to, n)
  1035. Xint from, to, n;
  1036. X{
  1037. X    if(cs && sf && sr) {
  1038. X        outs(tgoto(cs, from, to-1));
  1039. X        if(n<0)
  1040. X            while(n++)
  1041. X                outs(sr);
  1042. X        else
  1043. X            while(n--)
  1044. X                outs(sf);
  1045. X        outs(tgoto(cs, 0, li-1));
  1046. X    } 
  1047. X    else if(al && dl) {
  1048. X        if(n<0) {
  1049. X            int i=n;
  1050. X            outs(tgoto(cm, 0, to+n));
  1051. X            while(i++)
  1052. X                outs(dl);
  1053. X            outs(tgoto(cm, 0, from));
  1054. X            while(n++)
  1055. X                outs(al);
  1056. X        } 
  1057. X        else {
  1058. X            int i=n;
  1059. X            outs(tgoto(cm, 0, from));
  1060. X            while(i--)
  1061. X                outs(dl);
  1062. X            outs(tgoto(cm, 0, to-n));
  1063. X            while(n--)
  1064. X                outs(al);
  1065. X        }
  1066. X    }
  1067. X}
  1068. X
  1069. Xwperror(file)
  1070. Xchar *file;
  1071. X{
  1072. X    extern int errno;
  1073. X    extern char *sys_errlist[];
  1074. X
  1075. X    cmdline();
  1076. X    ctlouts(file);
  1077. X    ctlouts(": ");
  1078. X    ctlouts(errno?sys_errlist[errno]:emesg[xerrno]);
  1079. X    if(!display_up)
  1080. X        nl();
  1081. X}
  1082. X
  1083. Xfperror(prog, file)
  1084. Xchar *prog, *file;
  1085. X{
  1086. X    extern int errno;
  1087. X
  1088. X    fprintf(stderr, "%s -- ", prog);
  1089. X    if(errno)
  1090. X        perror(file);
  1091. X    else
  1092. X        fprintf(stderr, "%s: %s\n", file, emesg[xerrno]);
  1093. X}
  1094. X
  1095. Xtinit(name)
  1096. Xchar *name;
  1097. X{
  1098. X    char *termptr;
  1099. X    char tbuf[TERMBUF], *tmp;
  1100. X    int  intr();
  1101. X#ifdef BSD
  1102. X    int  stop();
  1103. X#endif
  1104. X
  1105. X    termptr = termbuf;
  1106. X
  1107. X    tgetent(tbuf, name);
  1108. X
  1109. X    tmp = tgetstr("pc", &termptr);
  1110. X    if(tmp) PC = *tmp;
  1111. X    UP = tgetstr("up", &termptr);
  1112. X    BC = tgetstr("bc", &termptr);
  1113. X    cm = tgetstr("cm", &termptr);
  1114. X    cs = tgetstr("cs", &termptr);
  1115. X    sf = tgetstr("sf", &termptr);
  1116. X    sr = tgetstr("sr", &termptr);
  1117. X    ce = tgetstr("ce", &termptr);
  1118. X    cl = tgetstr("cl", &termptr);
  1119. X    al = tgetstr("al", &termptr);
  1120. X    dl = tgetstr("dl", &termptr);
  1121. X    us = tgetstr("us", &termptr);
  1122. X    ue = tgetstr("ue", &termptr);
  1123. X    so = tgetstr("so", &termptr);
  1124. X    se = tgetstr("se", &termptr);
  1125. X    ti = tgetstr("ti", &termptr);
  1126. X    te = tgetstr("te", &termptr);
  1127. X    li = tgetnum("li");
  1128. X    co = tgetnum("co");
  1129. X    xn = tgetflag("xn");
  1130. X
  1131. X    nlines=li-3;
  1132. X
  1133. X#ifdef USG
  1134. X    ioctl(1, TCGETA, &rawbuf);
  1135. X    cookedbuf = rawbuf;
  1136. X    rawbuf.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  1137. X    rawbuf.c_cc[VMIN] = 1;
  1138. X    rawbuf.c_cc[VTIME] = 0;
  1139. X#else
  1140. X    gtty(1, &sgbuf);
  1141. X    ospeed=sgbuf.sg_ospeed;
  1142. X    quickmode=ospeed<10;
  1143. X    cookflags=sgbuf.sg_flags;
  1144. X    sgbuf.sg_flags = (sgbuf.sg_flags&~ECHO)|CBREAK;
  1145. X    rawflags=sgbuf.sg_flags;
  1146. X#endif
  1147. X    signal(SIGINT, intr);
  1148. X#ifdef BSD
  1149. X    signal(SIGTSTP, stop);
  1150. X#endif
  1151. X    rawtty();
  1152. X}
  1153. X
  1154. Xint tmode=0;
  1155. X
  1156. Xentty()
  1157. X{
  1158. X    if(!tmode)
  1159. X        outs(ti);
  1160. X    tmode=1;
  1161. X}
  1162. X
  1163. Xextty()
  1164. X{
  1165. X    if(tmode)
  1166. X        outs(te);
  1167. X    tmode=0;
  1168. X}
  1169. X
  1170. Xrawtty()
  1171. X{
  1172. X#ifdef USG
  1173. X    ioctl(1, TCSETA, &rawbuf);
  1174. X#else
  1175. X    sgbuf.sg_flags=rawflags;
  1176. X    stty(1, &sgbuf);
  1177. X#endif
  1178. X    entty();
  1179. X}
  1180. X
  1181. Xcooktty()
  1182. X{
  1183. X#ifdef USG
  1184. X    ioctl(1, TCSETA, &cookedbuf);
  1185. X#else
  1186. X    sgbuf.sg_flags=cookflags;
  1187. X    stty(1, &sgbuf);
  1188. X#endif
  1189. X    extty();
  1190. X}
  1191. X
  1192. Xintr()
  1193. X{
  1194. X    int intr();
  1195. X    signal(SIGINT, intr);
  1196. X    intrup=1;
  1197. X    bell();
  1198. X}
  1199. X
  1200. X#ifdef BSD
  1201. Xstop()
  1202. X{
  1203. X    int stop();
  1204. X    signal(SIGTSTP, stop);
  1205. X    intrup=1;
  1206. X    tend();
  1207. X    kill(getpid(), SIGSTOP);
  1208. X    rawtty();
  1209. X    display_up=0;
  1210. X}
  1211. X#endif
  1212. X
  1213. Xtend()
  1214. X{
  1215. X    cmdline();
  1216. X    cooktty();
  1217. X    fflush(stdout);
  1218. X}
  1219. X
  1220. Xchar *
  1221. Xpwd()
  1222. X#ifdef GETCWD
  1223. X{
  1224. X    static char mydir[FILENAME+1] = "";
  1225. X    char *getcwd();
  1226. X
  1227. X    return getcwd(mydir, FILENAME);
  1228. X}
  1229. X#else
  1230. X{
  1231. X    static char mydir[FILENAME] = "";
  1232. X    int  status;
  1233. X    int  pip[2];
  1234. X    int  n;
  1235. X    int  (*sigs[2])();
  1236. X
  1237. X    sigs[0] = signal(2, 1);
  1238. X    sigs[1] = signal(3, 1);
  1239. X
  1240. X    if(pipe(pip)<0)
  1241. X        return 0;
  1242. X
  1243. X    if(!fork()) {
  1244. X        close(1); 
  1245. X        dup(pip[1]);
  1246. X        close(pip[0]);
  1247. X        execl("/bin/pwd", "pwd", 0);
  1248. X        exit(-1);
  1249. X    }
  1250. X    close(pip[1]);
  1251. X    wait(&status);
  1252. X    signal(2, sigs[0]);
  1253. X    signal(3, sigs[1]);
  1254. X
  1255. X    if(status) {
  1256. X        close(pip[0]);
  1257. X        return "/";
  1258. X    }
  1259. X    n = read(pip[0], mydir, FILENAME);
  1260. X    close(pip[0]);
  1261. X    if(n<=0)
  1262. X        return "/";
  1263. X    mydir[n-1] = 0;
  1264. X    return mydir;
  1265. X}
  1266. X#endif
  1267. X
  1268. Xbrowse()
  1269. X{
  1270. X    int  c;
  1271. X    char *env;
  1272. X
  1273. X    if(env=getenv("BROWSE"))
  1274. X        macptr = env;
  1275. X
  1276. X    defmacs();
  1277. X    newdir();
  1278. X    redraw();
  1279. X    ended=0;
  1280. X
  1281. X    do {
  1282. X        if(intrup) {
  1283. X            intrup=0;    /* clear interrupt */
  1284. X            cmdline();    /* go to the command line */
  1285. X            outs("Interrupt");    /* let us know about it */
  1286. X            endmac();    /* clear macros */
  1287. X            clearin();    /* and input buffer */
  1288. X        }
  1289. X        here_i_am();
  1290. X        fflush(stdout);
  1291. X        c = getch();
  1292. X        cmd(c);
  1293. X    } 
  1294. X    while(!ended);
  1295. X}
  1296. X
  1297. Xclearin()
  1298. X{
  1299. X    fseek(stdin, 0L, 1); /* stay here messily */
  1300. X}
  1301. X
  1302. Xcmd(c)
  1303. Xchar c;
  1304. X{
  1305. X    int    i;
  1306. X
  1307. X    if(intrup)
  1308. X        return;
  1309. X
  1310. X    switch(c) {
  1311. X    case ' ':
  1312. X        if(isdir(entries[curr])) {
  1313. X            if(!cd(entries[curr]->e_name))
  1314. X                wperror(entries[curr]->e_name);
  1315. X        } else
  1316. X            if(!macro(c))
  1317. X                bell();
  1318. X            else
  1319. X                cmd(getch());
  1320. X        break;
  1321. X    case '&': 
  1322. X        syscom(0); 
  1323. X        break;
  1324. X    case '!': 
  1325. X        syscom(1); 
  1326. X        break;
  1327. X    case '=':
  1328. X        todir();
  1329. X        break;
  1330. X    case '?': 
  1331. X        sample(entries[curr]->e_name); 
  1332. X        break;
  1333. X    case '[':
  1334. X        define();
  1335. X        break;
  1336. X    case 'B'-'@':
  1337. X        prev(nlines);
  1338. X        break;
  1339. X    case 'D'-'@':
  1340. X        next(nlines/2);
  1341. X        break;
  1342. X    case 'F'-'@':
  1343. X        next(nlines);
  1344. X        break;
  1345. X    case 'H': 
  1346. X        curr=top; 
  1347. X        break;
  1348. X    case 'J': 
  1349. X        tail(); 
  1350. X        break;
  1351. X    case 'K': 
  1352. X        home(); 
  1353. X        break;
  1354. X    case 'L'-'@': 
  1355. X        redraw(); 
  1356. X        break;
  1357. X    case 'L': 
  1358. X        curr=bottom-1; 
  1359. X        break;
  1360. X    case 'M':
  1361. X        definitions();
  1362. X        break;
  1363. X    case 'N': 
  1364. X        next(nlines);
  1365. X        break;
  1366. X    case 'P': 
  1367. X        prev(nlines);
  1368. X        break;
  1369. X    case 'R': 
  1370. X        move(); 
  1371. X        break;
  1372. X    case 'S':
  1373. X        savedefs();
  1374. X        break;
  1375. X    case 'U'-'@':
  1376. X        prev(nlines/2);
  1377. X        break;
  1378. X    case 'D':
  1379. X    case 'd': 
  1380. X        if(getch()==c && !intrup)
  1381. X            remove(c=='D'); 
  1382. X        else
  1383. X            bell(); 
  1384. X        break;
  1385. X    case 'h': 
  1386. X        ccol=0; 
  1387. X        break;
  1388. X    case 'l': 
  1389. X        ccol=NCOL; 
  1390. X        break;
  1391. X    case '<':
  1392. X        quickmode=1;
  1393. X        if(display_up) {
  1394. X            todump=1;
  1395. X            at(0, 1);
  1396. X            header();
  1397. X        }
  1398. X        break;
  1399. X    case '+': case '^':
  1400. X        addname(c);
  1401. X        break;
  1402. X    case '(':
  1403. X        addperm();
  1404. X        break;
  1405. X    case ')':
  1406. X        delperm();
  1407. X        break;
  1408. X    case '>':
  1409. X        quickmode=0;
  1410. X        if(display_up) {
  1411. X            todump=1;
  1412. X            at(0, 1);
  1413. X            header();
  1414. X        }
  1415. X        break;
  1416. X    case 'J'-'@': 
  1417. X    case 'j': 
  1418. X        newline(); 
  1419. X        break;
  1420. X    case 'K'-'@': 
  1421. X    case 'k': 
  1422. X        upline(); 
  1423. X        break;
  1424. X    case 'n': 
  1425. X        next(nlines/2);
  1426. X        break;
  1427. X    case 'p': 
  1428. X        prev(nlines/2);
  1429. X        break;
  1430. X    case 'q':  case 'Z': case 'Q':
  1431. X        if(getchar()==c && !intrup)
  1432. X            ended=1;
  1433. X        else
  1434. X            bell();
  1435. X        break;
  1436. X    case 'r': 
  1437. X        reload(); 
  1438. X        break;
  1439. X    case 't':
  1440. X        tag();
  1441. X        break;
  1442. X    case 'T': case 'U':
  1443. X        tag_all(c=='T');
  1444. X        break;
  1445. X    default:
  1446. X        if(!macro(c))
  1447. X            bell();
  1448. X        else
  1449. X            cmd(getch()); /* make sure it does something */
  1450. X    }                                 /* and thus avoid unneeded redraws */
  1451. X}
  1452. X
  1453. Xcmdline()
  1454. X{
  1455. X    at(0, li-1);
  1456. X    outs(ce);
  1457. X}
  1458. X
  1459. Xnewdir()
  1460. X{
  1461. X    if(display_up)
  1462. X        at(0,0);
  1463. X    fflush(stdout);
  1464. X    dot=pwd();
  1465. X
  1466. X    if(!getdir())
  1467. X        wperror(dot);
  1468. X
  1469. X    curr=0;
  1470. X    top=0;
  1471. X    topline();
  1472. X    if(display_up)
  1473. X        todump=TRUE;
  1474. X}
  1475. X
  1476. Xreload()
  1477. X{
  1478. X    getdir();
  1479. X    curr=(curr>=bottom)?bottom-1:curr;
  1480. X    if(display_up) {
  1481. X        topline();
  1482. X        todump=TRUE;
  1483. X    }
  1484. X}
  1485. X
  1486. Xtopline()
  1487. X{
  1488. X    if(display_up)
  1489. X        at(0,0);
  1490. X    printf("%s: %d files", dot, nentries);
  1491. X    nl();
  1492. X}
  1493. X
  1494. Xredraw()
  1495. X{
  1496. X    outs(cl);
  1497. X    display_up=0;
  1498. X    topline();
  1499. X    at(0,1);
  1500. X    header();
  1501. X    todump=1;
  1502. X    display_up=1;
  1503. X}
  1504. X
  1505. Xdumpdata()
  1506. X{
  1507. X    at(0,2);
  1508. X    dump(top,bottom);
  1509. X    if(top+nlines>nentries) {
  1510. X        int i;
  1511. X        at(0, bottom-top+2);
  1512. X        for(i=bottom-top; i<nlines; i++) {
  1513. X            outc('~');
  1514. X            nl();
  1515. X        }
  1516. X    }
  1517. X}
  1518. X
  1519. Xupline()
  1520. X{
  1521. X     if(curr>0)
  1522. X         curr--;
  1523. X     else bell();
  1524. X}
  1525. X
  1526. Xhome()
  1527. X{
  1528. X    curr=0;
  1529. X}
  1530. X
  1531. Xnext(l)
  1532. X{
  1533. X     curr += l;
  1534. X     if(curr>=nentries) curr=nentries-1;
  1535. X}
  1536. X
  1537. Xprev(l)
  1538. X{
  1539. X     curr -= l;
  1540. X     if(curr<0) curr=0;
  1541. X}
  1542. X
  1543. Xtail()
  1544. X{
  1545. X    curr=nentries-1;
  1546. X}
  1547. X
  1548. Xnewline()
  1549. X{
  1550. X     if(curr<nentries-1)
  1551. X         curr++;
  1552. X     else
  1553. X        bell();
  1554. X}
  1555. X
  1556. Xhere_i_am()
  1557. X{
  1558. X    int c;
  1559. X    if(*macptr)
  1560. X        return;
  1561. X    if(todump)
  1562. X        display_up = 1;
  1563. X    if(!display_up) {
  1564. X        cmdline();
  1565. X        statout(entries[curr]->e_name,
  1566. X            &entries[curr]->e_stat,
  1567. X            entries[curr]->e_uname,
  1568. X            entries[curr]->e_gname,
  1569. X            entries[curr]->e_flags);
  1570. X        at(quickmode?1:ccol, li-1);
  1571. X        fflush(stdout);
  1572. X        if((c=getch())=='\n') {
  1573. X            redraw();
  1574. X            here_i_am();
  1575. X        } 
  1576. X        else
  1577. X            ungetch(c);
  1578. X     } else if(todump) {
  1579. X         if(!(curr-top > 0 && curr-top < nlines)) {
  1580. X             top = curr-nlines/2;
  1581. X             if(top<0) top=0;
  1582. X         }
  1583. X         dumpdata();
  1584. X         at(quickmode?1:ccol, curr-top+2);
  1585. X         todump=0;
  1586. X     } else {
  1587. X         int lines_to_scroll = curr-top;
  1588. X         if(lines_to_scroll > 0)
  1589. X             if((lines_to_scroll -= nlines-1) < 0)
  1590. X                 lines_to_scroll = 0;
  1591. X         if(lines_to_scroll < 1-nlines) {
  1592. X             top=curr;
  1593. X             at(0,2);
  1594. X             dump(top, bottom);
  1595. X         } else if(lines_to_scroll > nlines-1) {
  1596. X             top=curr-nlines+1;
  1597. X             at(0,2);
  1598. X             dump(top, bottom);
  1599. X         } else if(lines_to_scroll) {
  1600. X             scroll(2, nlines+2, lines_to_scroll);
  1601. X             top += lines_to_scroll;
  1602. X             if(lines_to_scroll < 0) {
  1603. X                 at(0, 2);
  1604. X                 dump(top, top-lines_to_scroll);
  1605. X             } else {
  1606. X                 at(0, 2+nlines-lines_to_scroll);
  1607. X                 dump(bottom-lines_to_scroll, bottom);
  1608. X             }
  1609. X         }
  1610. X         at(quickmode?1:ccol, curr-top+2);
  1611. X     }
  1612. X}
  1613. X
  1614. Xbell()
  1615. X{
  1616. X    outc(7);
  1617. X}
  1618. X
  1619. Xperform(command)
  1620. Xchar *command;
  1621. X{
  1622. X    char cmdbuf[MAXLINE];
  1623. X
  1624. X    cmdline();
  1625. X    extty();
  1626. X    outc('!');
  1627. X    printf(command, entries[curr]->e_name);
  1628. X    sprintf(cmdbuf, command, entries[curr]->e_name);
  1629. X
  1630. X    system(cmdbuf, 1);
  1631. X    entty();
  1632. X}
  1633. X
  1634. Xsystem(command, rdflag)
  1635. Xchar *command;
  1636. Xint rdflag; /* Should I redraw? */
  1637. X{
  1638. X    char scratch[32];
  1639. X    int status;
  1640. X    int (*sigint)(), (*sigquit)();
  1641. X    char c;
  1642. X
  1643. X    sigint=signal(2, 1);
  1644. X    sigquit=signal(3, 1);
  1645. X    cooktty();
  1646. X    fflush(stdout);
  1647. X    strcpy(scratch, entries[curr]->e_name);
  1648. X    if(!fork()) {
  1649. X        int i;
  1650. X        static char *envp[MAXARGC];
  1651. X        static char env[NCARGS];
  1652. X        char *hold;
  1653. X        char line[MAXLINE];
  1654. X        char *tmp;
  1655. X
  1656. X        signal(2,0);
  1657. X        signal(3,0);
  1658. X
  1659. X        if(!(efp=fopen(efname, "r"))) {
  1660. X            fputc('\n', stderr);
  1661. X            perror(efname);
  1662. X            execl(SHELL, SHELL, "-c", command, 0);
  1663. X            execl("/bin/sh", "sh", "-c", command, 0);
  1664. X            perror("/bin/sh");
  1665. X            exit(-77);
  1666. X        }
  1667. X
  1668. X        i=0;
  1669. X        tmp=hold=env;
  1670. X
  1671. X        while(!feof(efp)) {
  1672. X            fgets(line, MAXLINE, efp);
  1673. X            if(strlen(line)+(tmp-env)>NCARGS)
  1674. X                break;
  1675. X            if(line[0]=='$')
  1676. X                if(tmp>hold) {
  1677. X                    envp[i] = hold;
  1678. X                    i++;
  1679. X                    if(i > MAXARGC-2) break;
  1680. X                    tmp[-1]=0;   /* eat line-feed at end */
  1681. X                    hold = tmp;
  1682. X                }
  1683. X            strcpy(tmp, line+(line[0]=='$'));
  1684. X            tmp += strlen(tmp);
  1685. X        }
  1686. X        if(tmp>hold) {
  1687. X            envp[i] = hold;
  1688. X            i++;
  1689. X            tmp[-1]=0;               /* and eat this one as well */
  1690. X        }
  1691. X        sprintf(tmp, "FILE=%s", scratch);
  1692. X        envp[i++]=tmp;
  1693. X        envp[i]=0;
  1694. X
  1695. X        if(rdflag)
  1696. X            putchar('\n');
  1697. X        else
  1698. X            putchar('\r');
  1699. X        fflush(stdout);
  1700. X        execle(SHELL, SHELL, "-c", command, 0, envp);
  1701. X        execle("/bin/sh", "sh", "-c", command, 0, envp);
  1702. X        perror("/bin/sh");
  1703. X        exit(-77);
  1704. X    }
  1705. X    wait(&status);
  1706. X    signal(2, sigint);
  1707. X    signal(3, sigquit);
  1708. X    rawtty();
  1709. X
  1710. X    if(rdflag || status!=0)
  1711. X        display_up=0;
  1712. X}
  1713. X
  1714. Xchar
  1715. Xinps(buf, text, termin)
  1716. Xchar *buf;
  1717. Xchar *text;
  1718. Xchar termin;
  1719. X{
  1720. X    int i = 0;
  1721. X    char c, *ptr, *txp;
  1722. X
  1723. X    txp=text?text:"!";
  1724. X
  1725. X    while(!intrup &&
  1726. X        (fflush(stdout), c=getch()) != '\033' &&
  1727. X        c != '\n' &&
  1728. X        c != termin)
  1729. X        switch(c) {
  1730. X        case '\b': 
  1731. X        case '\177':
  1732. X            if(i>0) {
  1733. X                printf("\b \b");
  1734. X                i--;
  1735. X            } 
  1736. X            else
  1737. X                bell();
  1738. X            break;
  1739. X        case 'U'-'@':
  1740. X            txp=text?text:"!";
  1741. X        case 'X'-'@':
  1742. X            if(i>0)
  1743. X                while(i>0) {
  1744. X                    printf("\b \b");
  1745. X                    i--;
  1746. X                }
  1747. X            else
  1748. X                bell();
  1749. X            break;
  1750. X        case 'K'-'@':
  1751. X            if(*txp)
  1752. X                ctloutc(buf[i++] = *txp++);
  1753. X            break;
  1754. X        case '%':
  1755. X            for(ptr=entries[curr]->e_name; *ptr; ptr++)
  1756. X                ctlout(buf[i++] = *ptr);
  1757. X            standend();
  1758. X            break;
  1759. X        case '#':
  1760. X            for(ptr=dot; *ptr; ptr++)
  1761. X                ctlout(buf[i++] = *ptr);
  1762. X            standend();
  1763. X            break;
  1764. X        case '~':
  1765. X            for(ptr=HOME; *ptr; ptr++)
  1766. X                ctlout(buf[i++] = *ptr);
  1767. X            standend();
  1768. X            break;
  1769. X        case '@':
  1770. X            outc(c);
  1771. X            fflush(stdout);
  1772. X            c = getch();
  1773. X            if(!macro(c)) {
  1774. X                ungetch(c);
  1775. X                buf[i++]='@';
  1776. X            } 
  1777. X            else
  1778. X                outs("\b \b");
  1779. X            break;
  1780. X        case '$':
  1781. X            outc(c);
  1782. X            fflush(stdout);
  1783. X            c = getch();
  1784. X            if(c=='$') {
  1785. X                char tmp[10];
  1786. X                sprintf(tmp, "%d", getpid());
  1787. X                outs("\b \b");
  1788. X                for(ptr=tmp; *ptr; ptr++)
  1789. X                    ctlout(buf[i++] = *ptr);
  1790. X                standend();
  1791. X            } 
  1792. X            else if(!macbuf[c]) {
  1793. X                ungetch(c);
  1794. X                buf[i++]='$';
  1795. X            } 
  1796. X            else {
  1797. X                outs("\b \b");
  1798. X                for(ptr=macbuf[c]; *ptr; ptr++)
  1799. X                    ctlout(buf[i++] = *ptr);
  1800. X                standend();
  1801. X            }
  1802. X            break;
  1803. X        case '!':
  1804. X            while(*txp)
  1805. X                ctlout(buf[i++] = *txp++);
  1806. X            standend();
  1807. X            break;
  1808. X        case '\\':
  1809. X            outc(c);
  1810. X            fflush(stdout);
  1811. X            c=getch();
  1812. X            if(c=='~' || c=='%' || c=='#' ||
  1813. X                c=='\\' || c=='!' ||
  1814. X                c=='K'-'@' || c=='U'-'@' || c=='X'-'@' ||
  1815. X                c=='\b' || c=='\177' ||
  1816. X                c==termin || c=='\033' || c=='\n' ||
  1817. X                c=='@' || c=='$') {
  1818. X                outc('\b');
  1819. X                ctloutc(buf[i++]=c);
  1820. X                break;
  1821. X            } 
  1822. X            else if(c>='0' && c<='7') {
  1823. X                int n, val=0;
  1824. X                for(n=0; n<3 && c>='0' && c<='7'; n++) {
  1825. X                    val = val*8 + c-'0';
  1826. X                    outc('\b');
  1827. X                    ctloutc(val);
  1828. X                    c=getch();
  1829. X                }
  1830. X                ungetch(c);
  1831. X                c=buf[i++]=val;
  1832. X                break;
  1833. X            } 
  1834. X            else if(c=='^') {
  1835. X                outc('\b');
  1836. X                outc('^');
  1837. X                fflush(stdout);
  1838. X                c=getch();
  1839. X                if(c>='?'&&c<='_') {
  1840. X                    outc('\b');
  1841. X                    ctloutc(buf[i++]=(c-'@')&'\177');
  1842. X                    break;
  1843. X                } 
  1844. X                else if(c>='`'&&c<='~') {
  1845. X                    outc('\b');
  1846. X                    ctloutc(buf[i++]=c-'`');
  1847. X                    break;
  1848. X                } /* otherwise default */
  1849. X                else buf[i++]='^'; /* after adding caret */
  1850. X
  1851. X            } /* otherwise fall through to default */
  1852. X            else buf[i++]='\\'; /* after adding backslash */
  1853. X        default:
  1854. X            ctloutc(buf[i++] = c);
  1855. X            break;
  1856. X        }
  1857. X
  1858. X    buf[i] = 0;
  1859. X    return intrup?'\033':c;
  1860. X}
  1861. X
  1862. Xctlouts(s)
  1863. Xchar *s;
  1864. X{
  1865. X    int cnt = 0;
  1866. X
  1867. X    while(*s)
  1868. X        cnt += ctlout(*s++);
  1869. X    cnt += standend();
  1870. X
  1871. X    return cnt;
  1872. X}
  1873. X
  1874. Xctloutc(c)
  1875. Xchar c;
  1876. X{
  1877. X    int cnt;
  1878. X
  1879. X    cnt = ctlout(c);
  1880. X    cnt += standend();
  1881. X
  1882. X    return cnt;
  1883. X}
  1884. X
  1885. Xint somode = 0;
  1886. Xint ulmode = 0;
  1887. X
  1888. Xstandout()
  1889. X{
  1890. X    if(!somode) {
  1891. X        outs(so);
  1892. X        somode = 1;
  1893. X        if(xn) return 1;
  1894. X    }
  1895. X    return 0;
  1896. X}
  1897. X
  1898. Xunderline()
  1899. X{
  1900. X    if(!ulmode) {
  1901. X        outs(us);
  1902. X        ulmode = 1;
  1903. X        if(xn) return 1;
  1904. X    }
  1905. X    return 0;
  1906. X}
  1907. X
  1908. Xstandend()
  1909. X{
  1910. X    int cnt = 0;
  1911. X
  1912. X    if(somode) {
  1913. X        outs(se);
  1914. X        somode = 0;
  1915. X        if(xn) cnt++;
  1916. X    }
  1917. X    if(ulmode) {
  1918. X        outs(ue);
  1919. X        ulmode = 0;
  1920. X        if(xn) cnt++;
  1921. X    }
  1922. X    return cnt;
  1923. X}
  1924. X
  1925. Xctlout(c)
  1926. Xchar c;
  1927. X{
  1928. X    int cnt = 0;
  1929. X    if(c&'\200') {
  1930. X        cnt += underline();
  1931. X        cnt += ctlout(c&'\177');
  1932. X        return cnt;
  1933. X    } 
  1934. X    else if(c<' ' || c=='\177') {
  1935. X        cnt += standout();
  1936. X        outc((c+'@')&'\177');
  1937. X        cnt++;
  1938. X        return cnt;
  1939. X    } 
  1940. X    else {
  1941. X        cnt += standend();
  1942. X        outc(c);
  1943. X        cnt++;
  1944. X        return cnt;
  1945. X    }
  1946. X}
  1947. X
  1948. Xtodir()
  1949. X{
  1950. X    char cmdbuf[MAXLINE];
  1951. X    static char lastdir[MAXLINE] = ".";
  1952. X    char *slash, *rindex();
  1953. X
  1954. X    cmdline();
  1955. X    printf("goto ");
  1956. X    if(inps(cmdbuf, lastdir, 0)!='\033' && cmdbuf[0]) {
  1957. X        strcpy(lastdir, cmdbuf);
  1958. X        if(!cd(cmdbuf, 0)) {
  1959. X            if(!fgoto(cmdbuf))
  1960. X                if(slash=rindex(cmdbuf, '/')) {
  1961. X                    *slash++=0;
  1962. X                    if(cd(cmdbuf, 1)) {
  1963. X                        if(!fgoto(slash)) {
  1964. X                            errno=0;
  1965. X                            xerrno=NOMATCH;
  1966. X                            wperror(slash);
  1967. X                        }
  1968. X                    } else
  1969. X                        wperror(cmdbuf);
  1970. X                } else
  1971. X                    wperror(cmdbuf);
  1972. X        }
  1973. X    } 
  1974. X    else
  1975. X        killcmd();
  1976. X}
  1977. X
  1978. Xfgoto(file)
  1979. Xchar *file;
  1980. X{
  1981. X    int i;
  1982. X
  1983. X    for(i = 0; i<nentries; i++)
  1984. X        if(match(entries[i]->e_name, file)) {
  1985. X            curr=i;
  1986. X            return 1;
  1987. X        }
  1988. X
  1989. X    return 0;
  1990. X}
  1991. X
  1992. Xmatch(target, sample)
  1993. Xchar *target, *sample;
  1994. X{
  1995. X    while(*sample && *target==*sample) {
  1996. X        target++;
  1997. X        sample++;
  1998. X    }
  1999. X    return !*sample;
  2000. X}
  2001. X
  2002. Xkillcmd()
  2003. X{
  2004. X    if(!intrup) {
  2005. X        cmdline();
  2006. X        printf("Command killed");
  2007. X        if(!display_up)
  2008. X            nl();
  2009. X    }
  2010. X}
  2011. X
  2012. Xcd(dir, flag)
  2013. Xchar *dir;
  2014. Xint flag;
  2015. X{
  2016. X    if(flag) {
  2017. X        cmdline();
  2018. X        printf("cd %s\r", dir);
  2019. X    } 
  2020. X    else
  2021. X        outc('\r');
  2022. X    fflush(stdout);
  2023. X    if(access(dir, 5)==0 && chdir(dir)==0) {
  2024. X        newdir();
  2025. X        return 1;
  2026. X    } 
  2027. X    return 0;
  2028. X}
  2029. X
  2030. Xsyscom(rd)
  2031. Xint rd; /* should I redraw? */
  2032. X{
  2033. X    char buf[MAXLINE];
  2034. X    static char lastcmd[MAXLINE] = "";
  2035. X    char inps();
  2036. X
  2037. X    cmdline();
  2038. X    extty();
  2039. X    putchar(rd?'!':'&');
  2040. X    if(inps(buf, lastcmd, 0)=='\033') {
  2041. X        entty();
  2042. X        killcmd();
  2043. X        return;
  2044. X    } 
  2045. X    else
  2046. X        strcpy(lastcmd, buf);
  2047. X    system(buf, rd);
  2048. X    entty();
  2049. X}
  2050. X
  2051. Xisdir(entry)
  2052. Xstruct entry *entry;
  2053. X{
  2054. X    return((entry->e_stat.st_mode&S_IFMT)==S_IFDIR);
  2055. X}
  2056. X
  2057. Xsample(name)
  2058. Xchar *name;
  2059. X{
  2060. X    int col;
  2061. X    int c, i;
  2062. X    FILE *tfp;
  2063. X
  2064. X    if(!(tfp = fopen(name, "r"))) {
  2065. X        wperror(name);
  2066. X        return;
  2067. X    }
  2068. X
  2069. X    i=0;
  2070. X    do {
  2071. X        cmdline();
  2072. X        col = 0;
  2073. X        for(c=fgetc(tfp); col<72 && !feof(tfp); c=fgetc(tfp))
  2074. X            col+=ctlout(c);
  2075. X        standend();
  2076. X        if(display_up)
  2077. X            outc('\r');
  2078. X        else
  2079. X            outc('\n');
  2080. X    } 
  2081. X    while(!feof(tfp) && (i=getch())=='?');
  2082. X
  2083. X    fclose(tfp);
  2084. X
  2085. X    if(i && i!=' ' && i!='q' && i!='?')
  2086. X        ungetch(i);
  2087. X}
  2088. X
  2089. Xmacro(c)
  2090. Xchar c;
  2091. X{
  2092. X    if(c==NOMAC)
  2093. X        return 0;
  2094. X    else if(!macbuf[c])
  2095. X        return 0;
  2096. X    else if(c==c_macro) {
  2097. X        cmdline();
  2098. X        printf("Recursive macro.");
  2099. X        endmac();
  2100. X        return 0;
  2101. X    } 
  2102. X    else {
  2103. X        c_macro = c;
  2104. X        macptr = macbuf[c];
  2105. X        return 1;
  2106. X    }
  2107. X}
  2108. X
  2109. Xgetch()
  2110. X{
  2111. X    char c;
  2112. X
  2113. X    if(ungetptr>ungetbuf)
  2114. X        return *--ungetptr;
  2115. X    if(*macptr)
  2116. X        if(*macptr=='\007') {
  2117. X            macptr++;
  2118. X            if(*macptr!='\007')
  2119. X                return getchar();
  2120. X            else {
  2121. X                if((c=getchar()) != '\n')
  2122. X                    macptr--;
  2123. X                else
  2124. X                    macptr++;
  2125. X                return (c=='\n')?getch():c;
  2126. X            }
  2127. X        } 
  2128. X        else if(*macptr=='\\') {
  2129. X            if(macptr[1]=='\007')
  2130. X                macptr++;
  2131. X            return *macptr++;
  2132. X        } 
  2133. X        else
  2134. X            return *macptr++;
  2135. X    else {
  2136. X        endmac();
  2137. X        return getchar();
  2138. X    }
  2139. X}
  2140. X
  2141. Xendmac() {
  2142. X    c_macro=NOMAC;
  2143. X    macptr="";
  2144. X}
  2145. X
  2146. Xungetch(c)
  2147. Xchar c;
  2148. X{
  2149. X    if(ungetptr-ungetbuf>SMALLBUF)
  2150. X        return;
  2151. X    *ungetptr++=c;
  2152. X}
  2153. X
  2154. Xdefine()
  2155. X{
  2156. X    int c;
  2157. X    char buf[SMALLBUF];
  2158. X
  2159. X    cmdline();
  2160. X
  2161. X    printf("define ");
  2162. X    c = getch();
  2163. X
  2164. X    if(intrup)
  2165. X        return;
  2166. X
  2167. X    ctloutc(c);
  2168. X    printf(" as [");
  2169. X    if(inps(buf, macbuf[c], ']')=='\033') {
  2170. X        killcmd();
  2171. X        return;
  2172. X    }
  2173. X    printf("]");
  2174. X
  2175. X    defent(c, buf);
  2176. X}
  2177. X
  2178. Xdefent(c, buf)
  2179. Xchar c;
  2180. Xchar *buf;
  2181. X{
  2182. X    if(macbuf[c])
  2183. X        free(macbuf[c]);
  2184. X
  2185. X    if(!buf[0]) {
  2186. X        macbuf[c]=0;
  2187. X        return;
  2188. X    }
  2189. X
  2190. X    macbuf[c] = (char *)malloc(strlen(buf)+1);
  2191. X
  2192. X    if(!macbuf[c]) {
  2193. X        cmdline();
  2194. X        printf("No room");
  2195. X        return;
  2196. X    }
  2197. X
  2198. X    strcpy(macbuf[c], buf);
  2199. X}
  2200. X
  2201. Xdefmacs()
  2202. X{
  2203. X    defent(' ', "!more %\n");
  2204. X    defent('%', "!%\n");
  2205. X    defent('.', "=.");
  2206. X    defent('/', "=/");
  2207. X    defent('~', "=~");
  2208. X    defent('v', "!vi %\n");
  2209. X    defent('$', "!vi /tmp/br.env.$$\n");
  2210. X}
  2211. X
  2212. Xdefinitions()
  2213. X{
  2214. X    char *ptr;
  2215. X    int    i;
  2216. X
  2217. X    cmdline();
  2218. X    for(i=0; i<CHARSET; i++)
  2219. X        if(macbuf[i]) {
  2220. X            printf("define ");
  2221. X            ctloutc(i);
  2222. X            printf(" as [");
  2223. X            ctlouts(macbuf[i]);
  2224. X            printf("]\n");
  2225. X        }
  2226. X    display_up=0;
  2227. X}
  2228. X
  2229. Xsavedefs()
  2230. X{
  2231. X    int i;
  2232. X    char filename[MAXLINE];
  2233. X    static char lastfile[MAXLINE] = "/usr/tmp/macros";
  2234. X    FILE *fp;
  2235. X
  2236. X    cmdline();
  2237. X    outs("Save macros as ");
  2238. X
  2239. X    if(inps(filename, lastfile, '\033')=='\033') {
  2240. X        killcmd();
  2241. X        return;
  2242. X    }
  2243. X
  2244. X    strcpy(lastfile, filename);
  2245. X
  2246. X    if(!(fp = fopen(filename, "w"))) {
  2247. X        wperror(filename);
  2248. X        return;
  2249. X    }
  2250. X
  2251. X    for(i=1; i<CHARSET; i++)
  2252. X        if(macbuf[i])
  2253. X            fprintf(fp, "[%c%s]\n", i, macbuf[i]);
  2254. X
  2255. X    fclose(fp);
  2256. X}
  2257. X
  2258. Xdumpenv(envp)
  2259. Xchar **envp;
  2260. X{
  2261. X    if(!(efp=fopen(efname, "w"))) {
  2262. X        fperror(efname);
  2263. X        exit(-1);
  2264. X    }
  2265. X    while(*envp)
  2266. X        fprintf(efp, "$%s\n", *envp++);
  2267. X    fflush(efp);
  2268. X}
  2269. //END_OF_FILE
  2270. echo "End of archive."
  2271. # end of archive.
  2272. exit 0
  2273.  
  2274.  
  2275.